//
//
//
//
//
//
// TCPSocket.C

#include "TCPSocket.h"
#include "common.h"
#include "datatypes.h"
#include "NetAddr.h"
#include "StrStream.h"
#include "Exception.h"
#include <sys/socket.h>

TCPSocket::TCPSocket()
{
	SocketHdl hdl = Socket::GetSockHdl();
	hdl->_fileID = socket(AF_INET,   SOCK_STREAM,   0);
	if(-1 == hdl->_fileID)
	{
		hdl->_valid = false;
		Util::StrStream str;
		str << "Error create TCP socket : "
			<< strerror(errno);
		throw Exception(str);
	}

	hdl->_valid = true;
}

TCPSocket::TCPSocket(S32 fileID)
{
	SocketHdl hdl = Socket::GetSockHdl();
	hdl->_fileID = fileID;
	hdl->_valid = fileID == -1 ? false : true;
}

TCPSocket::TCPSocket(const TCPSocket& other) 
{}

TCPSocket& TCPSocket::operator=(const TCPSocket& other)
{
	if(this == &other)
		return *this;
	Socket::operator=(other);
	return *this;
}

TCPSocket::~TCPSocket()
{}

void TCPSocket::Connect(const NetAddr& addr, const TimeVal& inv)
{
	if(!addr.Valide())
		throw Exception("Invalide Internet Address");

	SocketHdl hdl = Socket::GetSockHdl();
	struct sockaddr_in lDestAddr;
	lDestAddr.sin_family = addr._afamily;
	lDestAddr.sin_port = addr._port;
	lDestAddr.sin_addr.s_addr = addr._ip;

	S32 ret = connect(hdl->_fileID, (struct sockaddr *)&lDestAddr, sizeof(struct sockaddr));
	if(-1 == ret)
	{
		Util::StrStream str;
		str << "Error connect : "
			<< strerror(errno);
		throw Exception(str);
	}
	_peerAddr = addr;
}

void TCPSocket::Bind(const NetAddr& addr)
{
	if(!addr.Valide())
		throw Exception("Invalide Bind Address");
	
	SocketHdl hdl = Socket::GetSockHdl();
	struct sockaddr_in lDestAddr;
	lDestAddr.sin_family = addr._afamily; 
	lDestAddr.sin_port = addr._port;
	lDestAddr.sin_addr.s_addr = INADDR_ANY;

	S32 ret = bind(hdl->_fileID, (struct sockaddr *)&lDestAddr, sizeof(struct sockaddr));
	if(-1 == ret)
	{
		Util::StrStream str;
		str << "Error bind : "
			<< strerror(errno);
		throw Exception(str);
	}
}

void TCPSocket::Listen(U32 backLog)
{
	SocketHdl hdl = Socket::GetSockHdl();
	S32 ret = listen(hdl->_fileID, backLog);
	if(-1 == ret)
	{
		Util::StrStream str;
		str << "Error listen : "
			<< strerror(errno);
		throw Exception(str);
	}
}

//
// perform the accept connection operation on this socket
TCPSocket TCPSocket::Accept(NetAddr& addr)
{
	SocketHdl hdl = Socket::GetSockHdl();
	struct sockaddr_in cliaddr;
	socklen_t len;
	len = sizeof(cliaddr);

	S32 newFD = accept(hdl->_fileID,
			(struct sockaddr *)&cliaddr,
			&len);
	if(-1 == newFD)
	{
		Util::StrStream str;
		str << "Error accept: "
			<< strerror(errno);
		throw Exception(str);
	}

	return TCPSocket(newFD);
}


bool TCPSocket::operator==(const TCPSocket& other)
{
	return Socket::operator==(other);
}
